/*-------------------------------------------------------------------------
   compiler.h

   Copyright (C) 2006, Maarten Brock, sourceforge.brock@dse.nl
   Portions of this file are Copyright 2014 Silicon Laboratories, Inc.
   http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt

   This library is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License 
   along with this library; see the file COPYING. If not, write to the
   Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301, USA.

   As a special exception, if you link this library with other files,
   some of which are compiled with SDCC, to produce an executable,
   this library does not by itself cause the resulting executable to
   be covered by the GNU General Public License. This exception does
   not however invalidate any other reasons why the executable file
   might be covered by the GNU General Public License.
-------------------------------------------------------------------------*/

 /*
  * Header file to overcome 8051 compiler differences for specifying
  * special function registers. The following compilers are supported:
  * SDCC, Keil, Raisonance, IAR, Hi-Tech, Tasking, Crossware, Wickenhaeuser.
  * Unfortunately not for use with Dunfield. The compilers are identified by
  * their unique predefined macros. See also:
  * http://predef.sourceforge.net/precomp.html
  *
  * SBIT and SFR define special bit and special function registers at the given
  * address. SFR16 and SFR32 define sfr combinations at adjacent addresses in
  * little-endian format. SFR16E and SFR32E define sfr combinations without
  * prerequisite byte order or adjacency. None of these multi-byte sfr
  * combinations will guarantee the order in which they are accessed when read
  * or written.
  * SFR16X and SFR32X for 16 bit and 32 bit xdata registers are not defined
  * to avoid portability issues because of compiler endianness.
  * This file is to be included in every microcontroller specific header file.
  * Example:
  *
  * // my_mcu.h: sfr definitions for my mcu
  * #include <compiler.h>
  *
  * SBIT  (P0_1, 0x80, 1);      // Port 0 pin 1
  *
  * SFR   (P0, 0x80);           // Port 0
  *
  * SFRX  (CPUCS, 0xE600);      // Cypress FX2 Control and Status register in xdata memory at 0xE600
  *
  * SFR16 (TMR2, 0xCC);         // Timer 2, lsb at 0xCC, msb at 0xCD
  *
  * SFR16E(TMR0, 0x8C8A);       // Timer 0, lsb at 0x8A, msb at 0x8C
  *
  * SFR32 (MAC0ACC, 0x93);      // SiLabs C8051F120 32 bits MAC0 Accumulator, lsb at 0x93, msb at 0x96
  *
  * SFR32E(SUMR, 0xE5E4E3E2);   // TI MSC1210 SUMR 32 bits Summation register, lsb at 0xE2, msb at 0xE5
  *
 */

#ifndef _DWIN_COMPILER_H
#define _DWIN_COMPILER_H

#include <config.h>

#ifndef __ASSEMBLY__

#undef data

/** SDCC - Small Device C Compiler
  * http://sdcc.sf.net
 */
#if defined (SDCC) || defined (__SDCC)

#ifndef SDCC
#define SDCC (__SDCC_VERSION_MAJOR*100+__SDCC_VERSION_MINOR*10+__SDCC_VERSION_PATCH)
#endif

#if (SDCC >= 300)

#define interrupt __interrupt
#define _asm __asm
#define _endasm __endasm
// #define bit __bit
// #define code __code
#define at __at

#endif

# define SEG_GENERIC
# define SEG_FAR   __xdata
# define SEG_DATA  __data
# define SEG_NEAR  __data
# define SEG_IDATA __idata
# define SEG_XDATA __xdata
# define SEG_PDATA __pdata
# define SEG_CODE  __code
# define SEG_BDATA __bdata

# define SBIT(name, addr, bit)  __sbit  __at(addr+bit)                  name
# define SFR(name, addr)        __sfr   __at(addr)                      name
# define SFRX(name, addr)       xdata volatile unsigned char __at(addr) name
# define SFR16(name, addr)      __sfr16 __at(((addr+1U)<<8) | addr)     name
# define SFR16E(name, fulladdr) __sfr16 __at(fulladdr)                  name
# define SFR32(name, addr)      __sfr32 __at(((addr+3UL)<<24) | ((addr+2UL)<<16) | ((addr+1UL)<<8) | addr) name
# define SFR32E(name, fulladdr) __sfr32 __at(fulladdr)                  name

# define INTERRUPT(name, vector) void name (void) interrupt (vector)
# define INTERRUPT_USING(name, vector, regnum) void name (void) interrupt (vector) using (regnum)
# define INTERRUPT_PROTO(name, vector) void name (void) interrupt (vector)
# define INTERRUPT_PROTO_USING(name, vector, regnum) void name (void) interrupt (vector) using (regnum)

# define FUNCTION_USING(name, return_value, parameter, regnum) return_value name (parameter) using (regnum)
# define FUNCTION_PROTO_USING(name, return_value, parameter, regnum) return_value name (parameter) using (regnum)
// Note: Parameter must be either 'void' or include a variable type and name. (Ex: char temp_variable)

# define SEGMENT_VARIABLE(name, vartype, locsegment) locsegment vartype name
# define VARIABLE_SEGMENT_POINTER(name, vartype, targsegment) targsegment vartype * name
# define SEGMENT_VARIABLE_SEGMENT_POINTER(name, vartype, targsegment, locsegment) targsegment vartype * locsegment name
# define SEGMENT_POINTER(name, vartype, locsegment) vartype * locsegment name
# define LOCATED_VARIABLE(name, vartype, locsegment, addr, init) locsegment __at(addr) vartype name = init
# define LOCATED_VARIABLE_NO_INIT(name, vartype, locsegment, addr) locsegment __at(addr) vartype name

// NOP () macro support
#define NOP() _asm NOP _endasm

// generic pointer memory type specifiers
#define GPTR
#define GPTR_MTYPE_DATA       0x40
#define GPTR_MTYPE_IDATA      0x40
#define GPTR_MTYPE_BDATA      0x40
#define GPTR_MTYPE_PDATA      0x60
#define GPTR_MTYPE_XDATA      0x00
#define GPTR_MTYPE_CODE       0x80

/** Keil C51
  * http://www.keil.com
 */

#elif defined(__C51__) || defined(__CX51__)

/// Used with pointers, declares a generic pointer.  Generic pointers
/// work with any memory space but are inefficient.
#define SEG_GENERIC

/// Declares a variable to be located in 8051 DATA space.
#define SEG_DATA data

/// Declares a variable to be located in 8051 IDATA space.
#define SEG_IDATA idata

/// Declares a variable to be located in 8051 XDATA space.
#define SEG_XDATA xdata

/// Declares a variable to be located in 8051 PDATA space.
#define SEG_PDATA pdata

/// Declares a variable to be located in 8051 BDATA (bit-addressable) space.
#define SEG_BDATA bdata

/// Declares a variable to be located in 8051 CODE space.
#define SEG_CODE code

/**************************************************************************//**
 * Declares a bit variable in a bit-addressable SFR or memory space.
 *
 * @param name The name of the bit variable.
 * @param address The address of the byte containing the bit.
 * @param bitnum The bit number (0-7) within the byte.
 *
 * This cannot be used to make any arbitrary SFR or variable into
 * a bit variable.  The underlying memory must support bit-addressability.
 *****************************************************************************/
#define SBIT(name, address, bitnum) sbit name = address^bitnum

/**************************************************************************//**
 * Declares an 8-bit special function register (SFR) variable.
 *
 * @param name The name of the SFR variable.
 * @param address The address of the SFR.
 *
 * This creates a C variable (8-bit) that maps to a physical special function
 * register of the 8051.  This cannot be used to make any arbitrary memory
 * location into an SFR.  The _address_ must map to a real SFR in the memory
 * map.
 *****************************************************************************/
#define SFR(name, address) sfr name = address

/**************************************************************************//**
 * Declares a 16-bit special function register (SFR) variable.
 *
 * @param name The name of the SFR variable.
 * @param address The address of the 16-bit SFR.
 *
 * This creates a C variable (16-bit) that maps to a physical special function
 * register of the 8051.  This cannot be used to make any arbitrary memory
 * location into an SFR.  The _address_ must map to a real 16-bit SFR in the
 * memory map.
 *****************************************************************************/
#define SFR16(name, address) sfr16 name = address

#ifndef __SLS_IDE__
/**************************************************************************//**
 * Define an interrupt handler function for an interrupt vector.
 *
 * @param name The name of the interrupt handler function.
 * @param vector The interrupt vector number.
 *
 * This macro defines a function to be an interrupt handler.  The _vector_
 * parameter is the 8051 interrupt vector number, not the address.  This
 * will cause the compiler to treat the function as the interrupt handler
 * and generate the appropriate prolog/epilog code.
 *
 * @note This macro is used to define the function implementation.  To declare
 * the interrupt function prototype, use @ref INTERRUPT_PROTO.
 *****************************************************************************/
#define INTERRUPT(name, vector) void name (void) interrupt vector

/**************************************************************************//**
 * Define an interrupt handler function using a specific register bank.
 *
 * @param name The name of the interrupt handler function.
 * @param vector The interrupt vector number.
 * @param regnum The register bank number (0-3).
 *
 * This macro defines a function to be an interrupt handler, using a specific
 * register bank for the interrupt code.  The _vector_ parameter is the 8051
 * interrupt vector number, not the address.  The _regnum_ parameter is the
 * register bank number (0-3) that will be used as general purpose registers
 * for the instructions in the compiled code.  Using dedicated register banks
 * for interrupt handlers allows the prolog code to just switch banks instead
 * of saving and restoring all the general purpose registers.  This can make
 * interrupt entry/exit faster but requires dedicating a register bank for
 * the interrupt handler.
 *
 * @note This macro is used to define the function implementation.  To declare
 * the interrupt function prototype, use @ref INTERRUPT_PROTO_USING.
 *****************************************************************************/
#define INTERRUPT_USING(name, vector, regnum)                             \
             void name (void) interrupt vector using regnum

/**************************************************************************//**
 * Declare an interrupt handler prototype for an interrupt vector.
 *
 * @param name The name of the interrupt handler function.
 * @param vector The interrupt vector number.
 *
 * This macro declares a function prototype for an interrupt handler.  The
 * _vector_ parameter is the 8051 interrupt vector number, not the address.
 * Declaring the function prototype this way will cause the compiler to
 * recognize that the function is an interrupt handler and not a normal C
 * function.
 *
 * @note This macro is used to declare a prototype for the interrupt function.
 * To define the interrupt function implementation, use @ref INTERRUPT.
 *****************************************************************************/
#define INTERRUPT_PROTO(name, vector) void name (void)

/**************************************************************************//**
 * Declare an interrupt handler prototype using a specific register bank.
 *
 * @param name The name of the interrupt handler function.
 * @param vector The interrupt vector number.
 * @param regnum The register bank number (0-3).
 *
 * This macro declares a function prototype for an interrupt handler, for a
 * function that uses a specific register bank for the interrupt code.  The
 * _vector_ parameter is the 8051 interrupt vector number, not the address.
 * The _regnum_ parameter is the register bank number (0-3) that will be used
 * as general purpose registers in the function.  Declaring the function
 * prototype this way will cause the compiler to recognize that the function
 * is an interrupt handler and is not a normal C function.
 *
 * @note This macro is used to declare a prototype for the interrupt function.
 * To define the interrupt function implementation,
 * use @ref INTERRUPT_USING.
 *****************************************************************************/
#define INTERRUPT_PROTO_USING(name, vector, regnum) void name (void)

/**************************************************************************//**
 * Define a function to use a specific register bank.
 *
 * @param name The name of the function.
 * @param returnType The data type of the function return value
 * (void, int, etc).
 * @param parameters One or more C function parameters (type and name).
 * @param regnum The register bank number (0-3).
 *
 * This macro defines a function that uses a specific register bank.  The
 * _regnum_ parameter is the register bank number (0-3) that will be used as
 * general purpose registers for the instructions in the compiled function
 * code.  Using dedicated register banks for a function can reduce the amount
 * of registers saving and restoring needed on entry and exit to the
 * function.  However, this is an advanced feature and you should not use it
 * unless you fully understand how and when to use register banking.
 *
 * You must specify the _returnType_ which is the type of the function.  It
 * can be `void` or any other C type or typedef.  The _parameters_ argument
 * is the list of function parameters.  It can be `void` or else it must be
 * a parameter data type and name.  It can also be multiple parameters but
 * they must be enclosed in parentheses and separated by commas.
 *
 * __Example__
 *
 * ~~~~~~~~.c
 * // The following is used to implement a function with the following
 * // signature, and that uses register bank 3 ...
 * uint16_t myFunction(uint8_t parm1, uint8_t parm2);
 *
 * FUNCTION_USING(myFunction, uint16_t, (uint8_t parm1, uint8_t parm2), 3)
 * {
 *   // Function implementation body
 * }
 * ~~~~~~~~
 *
 * @note This macro is used to define the function implementation.  To declare
 * the function prototype, use @ref FUNCTION_PROTO_USING.
 *****************************************************************************/
#define FUNCTION_USING(name, returnType, parameters, regnum)              \
             return_value name (parameter) using regnum

/**************************************************************************//**
 * Declare a function that uses a specific register bank.
 *
 * @param name The name of the function.
 * @param returnType The data type of the function return value
 * (void, int, etc).
 * @param parameters One or more C function parameters (type and name).
 * @param regnum The register bank number (0-3).
 *
 * This macro declares a function prototype for a C function that uses a
 * specific register its working registers.  See the documentation for
 * @ref FUNCTION_USING for an explanation of the macro arguments.  This is
 * an advanced feature.
 *
 * @note This macro is used to declare a prototype for the function.  To
 * define the function implementation, use @ref FUNCTION_USING.
 *****************************************************************************/
#define FUNCTION_PROTO_USING(name, returnType, parameters, regnum)        \
             return_value name (parameter)

/**************************************************************************//**
 * Declare a variable to be located in a specific memory segment.
 *
 * @param name The variable name.
 * @param vartype The variable data type.
 * @param memseg The memory segment to use for the variable.
 *
 * This macro declares a variable to be located in a specific memory area
 * (or segment) of the 8051 memory space.  It is only necessary to use this
 * macro if you want to force the variable into a specific memory space instead
 * of the default memory space used by the compiler.  The segment can be
 * one of the following:
 *
 * - @ref SEG_DATA
 * - @ref SEG_IDATA
 * - @ref SEG_BDATA
 * - @ref SEG_PDATA
 * - @ref SEG_XDATA
 * - @ref SEG_CODE
 *
 * __Example__
 *
 * ~~~~~~~~.c
 * // The following macro can be used to create a variable located in
 * // XDATA with the following signature:
 * uint8_t myVar;
 *
 * SEGMENT_VARIABLE(myVar, uint8_t, SEG_XDATA);
 * ~~~~~~~~
 *****************************************************************************/
#define SEGMENT_VARIABLE(name, vartype, memseg) vartype memseg name

/**************************************************************************//**
 * Declare a memory segment specific pointer variable.
 *
 * @param name The pointer variable name.
 * @param vartype The pointer data type.
 * @param targseg The target memory segment for the pointer.
 *
 * This macro declares a pointer that points at a specific memory area
 * (or segment).  The memory segment of the pointer variable itself is not
 * specified and the default is used.  The segment can be one of the following:
 *
 * - @ref SEG_DATA
 * - @ref SEG_IDATA
 * - @ref SEG_BDATA
 * - @ref SEG_PDATA
 * - @ref SEG_XDATA
 * - @ref SEG_CODE
 *
 * __Example__
 *
 * ~~~~~~~~.c
 * // The following macro can be used to create a pointer that points to
 * // a location in XDATA with the following signature:
 * uint8_t *pVar; // where pVar is pointing at XDATA
 *
 * VARIABLE_SEGMENT_POINTER(pVar, uint8_t, SEG_XDATA);
 * ~~~~~~~~
 *****************************************************************************/
#define VARIABLE_SEGMENT_POINTER(name, vartype, targseg)                  \
             vartype targseg * name

/**************************************************************************//**
 * Declare a memory segment specific pointer variable, in a specific segment.
 *
 * @param name The pointer variable name.
 * @param vartype The pointer data type.
 * @param targseg The target memory segment for the pointer.
 * @param memseg The memory segment to use for the pointer variable.
 *
 * This macro declares a pointer that points at a specific memory area
 * (or segment).  The pointer variable itself is also located in a specified
 * memory segment by _memseg_.  The arguments _targseg_ and _memseg_ can be
 * one of the following:
 *
 * - @ref SEG_DATA
 * - @ref SEG_IDATA
 * - @ref SEG_BDATA
 * - @ref SEG_PDATA
 * - @ref SEG_XDATA
 * - @ref SEG_CODE
 *
 * __Example__
 *
 * ~~~~~~~~.c
 * // The following macro can be used to create a pointer that points to
 * // a location in XDATA while the pointer itself is located in DATA, with
 * // the following signature:
 * uint8_t *pVar; // where pVar is located in DATA and is pointing at XDATA
 *
 * SEGMENT_VARIABLE_SEGMENT_POINTER(pVar, uint8_t, SEG_XDATA, SEG_DATA);
 * ~~~~~~~~
 *****************************************************************************/
#define SEGMENT_VARIABLE_SEGMENT_POINTER(name, vartype, targseg, memseg)  \
             vartype targseg * memseg name

/**************************************************************************//**
 * Declare a generic pointer variable that is located in a specific segment.
 *
 * @param name The pointer variable name.
 * @param vartype The pointer data type.
 * @param memseg The memory segment to use for the pointer variable.
 *
 * This macro declares a pointer that is a generic pointer.  This means it can
 * point at any kind of memory location.  However the pointer variable itself
 * is located in a specific memory segment by _memseg_, which can be one of
 * the following:
 *
 * - @ref SEG_DATA
 * - @ref SEG_IDATA
 * - @ref SEG_BDATA
 * - @ref SEG_PDATA
 * - @ref SEG_XDATA
 * - @ref SEG_CODE
 *
 * __Example__
 *
 * ~~~~~~~~.c
 * // The following macro can be used to create a generic pointer that
 * // is located in DATA and points at any memory type, with the
 * // following signature:
 * uint8_t *pVar; // where pVar is located in DATA and is a generic pointer
 *
 * SEGMENT_POINTER(pVar, uint8_t, SEG_DATA);
 * ~~~~~~~~
 *****************************************************************************/
#define SEGMENT_POINTER(name, vartype, memseg) vartype * memseg name

/**************************************************************************//**
 * Declare an uninitialized variable that is located at a specific address.
 *
 * @param name The variable name.
 * @param vartype The variable data type.
 * @param memseg The memory segment to use for the variable.
 * @param address The memory address of the variable.
 *
 * This macro allows declaring a variable that can be placed at a specific
 * location in memory.  This can only be used for variables that do not need
 * initializers.  The _address_ is the memory address within the specified
 * segment.  The memory segment, _memseg_, can be one of the following:
 *
 * - @ref SEG_DATA
 * - @ref SEG_IDATA
 * - @ref SEG_BDATA
 * - @ref SEG_PDATA
 * - @ref SEG_XDATA
 * - @ref SEG_CODE
 *
 * __Example__
 *
 * ~~~~~~~~.c
 * // The following declares a variable located at 0x4000 in XDATA with
 * // the following signature:
 * uint8_t myMemVar;
 *
 * LOCATED_VARIABLE_NO_INIT(myMemVar, uint8_t, SEG_DATA, 0x4000);
 * ~~~~~~~~
 *****************************************************************************/
#define LOCATED_VARIABLE_NO_INIT(name, vartype, memseg, address)          \
             vartype memseg name _at_ address


#else  // __SLS_IDE__ : Macros defined to remove syntax errors within Simplicity Studio
#define INTERRUPT(name, vector) void name (void)
#define INTERRUPT_USING(name, vector, regnum) void name (void)
#define INTERRUPT_PROTO(name, vector) void name (void)
#define INTERRUPT_PROTO_USING(name, vector, regnum) void name (void)

#define FUNCTION_USING(name, return_value, parameter, regnum) return_value name (parameter)
#define FUNCTION_PROTO_USING(name, return_value, parameter, regnum) return_value name (parameter)
// Note: Parameter must be either 'void' or include a variable type and name. (Ex: char temp_variable)

#define SEGMENT_VARIABLE(name, vartype, locsegment) vartype name
#define VARIABLE_SEGMENT_POINTER(name, vartype, targsegment) vartype * name
#define SEGMENT_VARIABLE_SEGMENT_POINTER(name, vartype, targsegment, locsegment) vartype * name
#define SEGMENT_POINTER(name, vartype, locsegment) vartype * name
#define LOCATED_VARIABLE_NO_INIT(name, vartype, locsegment, addr) vartype name
#endif // __SLS_IDE__

// Declaration of Keil intrinisc
extern void _nop_(void);
/// Macro to insert a no-operation (NOP) instruction.
#define NOP() _nop_()

// Generic pointer memory segment constants.
#define GPTR                   ///< Generic pointer indeterminate type.
#define GPTR_MTYPE_DATA  0x00  ///< Generic pointer for DATA segment.
#define GPTR_MTYPE_IDATA 0x00  ///< Generic pointer for IDATA segment.
#define GPTR_MTYPE_BDATA 0x00  ///< Generic pointer for BDATA segment.
#define GPTR_MTYPE_PDATA 0xFE  ///< Generic pointer for PDATA segment.
#define GPTR_MTYPE_XDATA 0x01  ///< Generic pointer for XDATA segment.
#define GPTR_MTYPE_CODE  0xFF  ///< Generic pointer for CODE segment.

/** Raisonance
  * http://www.raisonance.com
 */
#elif defined __RC51__

# define SEG_GENERIC generic     //SEG_GENERIC only applies to pointers in Raisonance, not variables.
# define SEG_FAR   xdata
# define SEG_DATA  data
# define SEG_NEAR  data
# define SEG_IDATA idata
# define SEG_XDATA xdata
# define SEG_PDATA pdata
# define SEG_CODE  code
# define SEG_BDATA bdata

# define SBIT(name, addr, bit)  at (addr+bit) sbit         name
# define SFR(name, addr)        sfr at addr                name
# define SFR16(name, addr)      sfr16 at addr              name
# define SFR16E(name, fulladdr) /* not supported */
# define SFR32(name, fulladdr)  /* not supported */
# define SFR32E(name, fulladdr) /* not supported */

# define INTERRUPT(name, vector) void name (void) interrupt vector
# define INTERRUPT_USING(name, vector, regnum) void name (void) interrupt vector using regnum
# define INTERRUPT_PROTO(name, vector) void name (void)
# define INTERRUPT_PROTO_USING(name, vector, regnum) void name (void)

# define FUNCTION_USING(name, return_value, parameter, regnum) return_value name (parameter) using regnum
# define FUNCTION_PROTO_USING(name, return_value, parameter, regnum) return_value name (parameter)
// Note: Parameter must be either 'void' or include a variable type and name. (Ex: char temp_variable)

# define SEGMENT_VARIABLE(name, vartype, locsegment) vartype locsegment name
# define VARIABLE_SEGMENT_POINTER(name, vartype, targsegment) vartype targsegment * name
# define SEGMENT_VARIABLE_SEGMENT_POINTER(name, vartype, targsegment, locsegment) vartype targsegment * locsegment name
# define SEGMENT_POINTER(name, vartype, locsegment) vartype * locsegment name
# define LOCATED_VARIABLE(name, vartype, locsegment, addr, init) at addr locsegment vartype name
# define LOCATED_VARIABLE_NO_INIT(name, vartype, locsegment, addr) at addr locsegment vartype name

// NOP () macro support -- NOP is opcode 0x00
#define NOP() asm { 0x00 }

// generic pointer memory type specifiers
#define GPTR
#define GPTR_MTYPE_DATA       0x04
#define GPTR_MTYPE_IDATA      0x01
#define GPTR_MTYPE_BDATA      0x04
#define GPTR_MTYPE_PDATA      0x03
#define GPTR_MTYPE_XDATA      0x02
#define GPTR_MTYPE_CODE       0x05

/** IAR 8051
  * http://www.iar.com
 */
#elif defined __ICC8051__

#include <stdbool.h>
#include <intrinsics.h>

# define SBIT(name, addr, bit)  __bit __no_init volatile bool name @ (addr+bit)
# define SFR(name, addr)        __sfr __no_init volatile unsigned char name @ addr
# define SFRX(name, addr)       __xdata __no_init volatile unsigned char name @ addr
# define SFR16(name, addr)      __sfr __no_init volatile unsigned int  name @ addr
# define SFR16E(name, fulladdr) /* not supported */
# define SFR32(name, fulladdr) /* not supported */
# define SFR32E(name, fulladdr) /* not supported */

# define SEG_GENERIC __generic
# define SEG_FAR  __xdata
# define SEG_DATA __data
# define SEG_NEAR __data
# define SEG_IDATA __idata
# define SEG_XDATA __xdata
# define SEG_PDATA __pdata
# define SEG_CODE  __code
# define SEG_BDATA __bdata

#define bit bool

# define _PPTOSTR_(x) #x
# define _PPARAM_(address) _PPTOSTR_(vector=address * 8 + 3)
# define _PPARAM2_(regbank) _PPTOSTR_(register_bank=regbank)
# define INTERRUPT(name, vector) _Pragma(_PPARAM_(vector)) __interrupt void name(void)
# define INTERRUPT_PROTO(name, vector)  __interrupt void name(void)
# define INTERRUPT_USING(name, vector, regnum) _Pragma(_PPARAM2_(regnum)) _Pragma(_PPARAM_(vector)) __interrupt void name(void)
# define INTERRUPT_PROTO_USING(name, vector, regnum) __interrupt void name(void)

# define FUNCTION_USING(name, return_value, parameter, regnum) /* not supported */
# define FUNCTION_PROTO_USING(name, return_value, parameter, regnum) /* not supported */
// Note: IAR does not support functions using different register banks. Register
//       banks can only be specified in interrupts. If a function is called from
//       inside an interrupt, it will use the same register bank as the interrupt.

# define SEGMENT_VARIABLE(name, vartype, locsegment)  locsegment vartype name
# define VARIABLE_SEGMENT_POINTER(name, vartype, targsegment) vartype targsegment  * name
# define SEGMENT_VARIABLE_SEGMENT_POINTER(name, vartype, targsegment, locsegment) vartype targsegment * locsegment name

# define LOCATED_VARIABLE(name, vartype, locsegment, addr, init) locsegment __no_init vartype name @ addr

#define NOP() __no_operation();

// generic pointer memory type specifiers
#define GPTR
#define GPTR_MTYPE_DATA       0x01
#define GPTR_MTYPE_IDATA      0x01
#define GPTR_MTYPE_BDATA      0x01
#define GPTR_MTYPE_PDATA      0x00
#define GPTR_MTYPE_XDATA      0x00
#define GPTR_MTYPE_CODE       0x80

/** Tasking / Altium
  * http://www.altium.com/tasking
 */
#elif defined _CC51

# define SEG_GENERIC
# define SEG_FAR   _xdat
# define SEG_DATA  _data
# define SEG_NEAR  _data
# define SEG_IDATA _idat
# define SEG_XDATA _xdat
# define SEG_PDATA _pdat
# define SEG_CODE  _rom
# define SEG_BDATA _bdat

# define SBIT(name, addr, bit)  _sfrbit  name _at(addr+bit)
# define SFR(name, addr)        _sfrbyte name _at(addr)
# define SFRX(name, addr)       _xdat volatile unsigned char name _at(addr)
#if _CC51 > 71
# define SFR16(name, addr)      _sfrword _little name _at(addr)
#else
# define SFR16(name, addr)      /* not supported */
#endif
# define SFR16E(name, fulladdr) /* not supported */
# define SFR32(name, fulladdr)  /* not supported */
# define SFR32E(name, fulladdr) /* not supported */

# define INTERRUPT(name, vector) _interrupt (vector) void name (void)
# define INTERRUPT_USING(name, vector, regnum) _interrupt (vector) _using(regnum) void name (void)
# define INTERRUPT_PROTO(name, vector) _interrupt (vector) void name (void)
# define INTERRUPT_PROTO_USING(name, vector, regnum) _interrupt (vector) _using(regnum) void name (void)

// When calling FUNCTION_USING in Tasking, the function must be called from an interrupt or Main which
// is also using the same register bank. If not, the compiler will generate an error.
# define FUNCTION_USING(name, return_value, parameter, regnum) _using(regnum) return_value name (parameter)
# define FUNCTION_PROTO_USING(name, return_value, parameter, regnum) _using(regnum) return_value name (parameter)
// Note: Parameter must be either 'void' or include a variable type and name. (Ex: char temp_variable)

# define SEGMENT_VARIABLE(name, vartype, locsegment) vartype locsegment name
# define VARIABLE_SEGMENT_POINTER(name, vartype, targsegment) vartype targsegment * name
# define SEGMENT_VARIABLE_SEGMENT_POINTER(name, vartype, targsegment, locsegment) vartype targsegment * locsegment name
# define LOCATED_VARIABLE(name, vartype, locsegment, addr, init) vartype locsegment name _at( addr )

// NOP () macro support
extern void _nop (void);
#define NOP() _nop()


/** Hi-Tech 8051
  * http://www.htsoft.com
 */
#elif defined HI_TECH_C

# define SEG_GENERIC
# define SEG_FAR   far
# define SEG_DATA  data
# define SEG_NEAR  near
# define SEG_IDATA idata
# define SEG_XDATA xdata
# define SEG_PDATA pdata
# define SEG_CODE  code
# define SEG_BDATA bdata


# define SBIT(name, addr, thebit) static volatile bit name @ (addr + thebit)
# define SFR(name, addr)          static volatile unsigned char name @ addr
# define SFR16(name, addr)        static volatile unsigned int name @ addr
# define SFR16E(name, fulladdr) /* not supported */
# define SFR32(name, fulladdr)  /* not supported */
# define SFR32E(name, fulladdr) /* not supported */

# define INTERRUPT(name, vector)       void name (void) interrupt vector
# define INTERRUPT_PROTO(name, vector)
# define INTERRUPT_USING(name, vector, regnum) void name (void) interrupt vector using regnum
# define INTERRUPT_PROTO_USING(name, vector, regnum)

# define FUNCTION_USING(name, return_value, parameter, regnum) /* not supported */
# define FUNCTION_PROTO_USING(name, return_value, parameter, regnum) /* not supported */
// Note: Hi-Tech does not support functions using different register banks. Register
//       banks can only be specified in interrupts. If a function is called from
//       inside an interrupt, it will use the same register bank as the interrupt.

# define SEGMENT_VARIABLE(name, vartype, locsegment) locsegment vartype name
# define VARIABLE_SEGMENT_POINTER(name, vartype, targsegment) targsegment vartype * name
# define SEGMENT_VARIABLE_SEGMENT_POINTER(name, vartype, targsegment, locsegment) targsegment vartype * locsegment name
# define LOCATED_VARIABLE(name, vartype, locsegment, addr, init) locsegment vartype name @ addr

// NOP () macro support
#define NOP() asm(" nop ")

/** Crossware
  * http://www.crossware.com
 */
#elif defined _XC51_VER
# define SBIT(name, addr, bit)  _sfrbit  name = (addr+bit)
# define SFR(name, addr)        _sfr     name = addr
# define SFRX(name, addr)       volatile unsigned char _xdata name _at addr
# define SFR16(name, addr)      _sfrword name = addr
# define SFR16E(name, fulladdr) /* not supported */
# define SFR32(name, fulladdr)  /* not supported */
# define SFR32E(name, fulladdr) /* not supported */

/** Wickenhaeuser
  * http://www.wickenhaeuser.de
 */
#elif defined __UC__
# define SBIT(name, addr, bit)  unsigned char bit  name @ (addr+bit)
# define SFR(name, addr)        near unsigned char name @ addr
# define SFRX(name, addr)       xdata volatile unsigned char name @ addr
# define SFR16(name, addr)      /* not supported */
# define SFR16E(name, fulladdr) /* not supported */
# define SFR32(name, fulladdr)  /* not supported */
# define SFR32E(name, fulladdr) /* not supported */

/** default
  * unrecognized compiler
 */
#else

# define SEG_GENERIC
# define SEG_FAR
# define SEG_DATA
# define SEG_NEAR
# define SEG_IDAT
# define SEG_XDATA
# define SEG_PDATA
# define SEG_CODE
# define SEG_BDATA
# define reentrant

# define SBIT(name, addr, bit)  volatile bool           name
# define SFR(name, addr)        volatile unsigned char  name
# define SFRX(name, addr)       volatile unsigned char  name
# define SFR16(name, addr)      volatile unsigned short name
# define SFR16E(name, fulladdr) volatile unsigned short name
# define SFR32(name, fulladdr)  volatile unsigned long  name
# define SFR32E(name, fulladdr) volatile unsigned long  name

#endif

#define CONST(_Type)  const _Type SEG_CODE

#define data _data

#ifndef PACKED
#if defined(__GNUC__) \
	|| defined(__XCC__) \
	|| defined(TARGET_LINUX32) \
	|| defined(TARGET_LINUX64)
# define PACKED  __attribute__((packed))
#else
# define PACKED
#endif
#endif

#endif /*  __ASSEMBLY__ */

#endif //_DWIN_COMPILER_H
